//
// Created by Zeppyrz on 2025/11/5.
//

#include "FileServerTask.h"

#include <cstring>
#include <iostream>

#include "Tools.h"

namespace ZeDisk {

std::mutex FileServerTask::cur_dir_mtx_;
std::string FileServerTask::current_directory_ = ".";

void FileServerTask::HandleMessage(const Message *msg) {
  CommonTask::HandleMessage(msg);
  switch (msg->head.type) {
    case MSG_TYPE_GETDIR:
      std::cout << "MSG_TYPE_GETDIR" << std::endl;
      GetDirectory(msg);
      break;
    case MSG_TYPE_UPLOAD_INFO:
      std::cout << "MSG_TYPE_UPLOAD_INFO" << std::endl;
      UploadFile(msg);
      break;
    case MSG_TYPE_DOWNLOAD_INFO:
      std::cout << "MSG_TYPE_DOWNLOAD_INFO" << std::endl;
      DownloadFile(msg);
      break;
    case MSG_TYPE_DOWNLOAD_COMPLETE:
      std::cout << "MSG_TYPE_DOWNLOAD_COMPLETE" << std::endl;
      break;
    default:
      break;
  }
}

void FileServerTask::WriteCallback() {
  CommonTask::WriteCallback();

  if (!inputfile_.is_open()) return;

  inputfile_.read(read_buffer_, sizeof(read_buffer_));
  int len = inputfile_.gcount();
  if (len <= 0) {
    inputfile_.close();
    return;
  }

  WriteRawMessage(read_buffer_, len);
  if (inputfile_.eof()) {
    inputfile_.close();
  }
}

void FileServerTask::HandleRawMessage(void *data, int size) {
  CommonTask::HandleRawMessage(data, size);
  if (!data || size < 0 || !outfile_.is_open()) {
    return;
  }
  outfile_.write(static_cast<char *>(data), size);
  upload_size_ += size;

  if (upload_size_ == file_size_) {
    std::cout << "[INFO] Server upload file size: " << file_size_ << " Success"
              << std::endl;
    outfile_.close();
    Message _msg;
    _msg.head.type = MSG_TYPE_UPLOAD_COMPLETE;
    _msg.head.size = 3;
    _msg.data = const_cast<char *>("OK");
    WriteMessage(&_msg);
  }
}

void FileServerTask::GetDirectory(const Message *msg) {
  std::string dir(msg->data, msg->head.size);
  std::cout << "[INFO] Client Request dir: " << dir << std::endl;
  set_current_directory(dir);
  auto res = Tools::GetDirectory(get_current_directory());
  Message _msg;
  _msg.head.type = MSG_TYPE_DIRLIST;
  _msg.head.size = res.size() + 1;  // 发送/0
  _msg.data = const_cast<char *>(res.c_str());
  WriteMessage(&_msg);
}

void FileServerTask::UploadFile(const Message *msg) {
  // 1. 获取文件名和大小
  if (!msg->data || msg->head.size <= 0) return;
  std::string str(msg->data, msg->head.size);
  if (str.empty()) return;

  // 2. 打开本地文件
  int pos = str.find_last_of(",");
  if (pos == std::string::npos) return;
  std::string filename = str.substr(0, pos);
  if (pos + 1 >= str.size()) return;
  std::string tmp = str.substr(pos + 1, str.size() - pos - 1);

  std::cout << "[INFO] Client Upload file: " << filename << " size: " << tmp
            << std::endl;

  file_size_ = atoi(tmp.c_str());
  if (file_size_ <= 0) return;
  std::string filepath = get_current_directory() + filename;
  std::cout << "[INFO] Server store filepath: " << filepath << std::endl;
  outfile_.open(filepath, std::ios::out | std::ios::binary);
  if (!outfile_.is_open()) {
    std::cout << "[ERROR] Failed to open file for writing: " << filepath
              << std::endl;
    return;
  }
  std::cout << "[INFO] Server store filepath: " << filepath << " Success"
            << std::endl;

  // 3. 回复准备接受消息
  Message _msg;
  _msg.head.type = MSG_TYPE_UPLOAD_ACCEPT;
  _msg.head.size = 3;
  _msg.data = const_cast<char *>("OK");
  WriteMessage(&_msg);

  // 开始接收文件
  is_recv_msg() = false;  // 停止接受消息，开始接受文件数据
  upload_size_ = 0;
}

void FileServerTask::DownloadFile(const Message *msg) {
  if (!msg->data || msg->head.size <= 0) return;
  // 打开文件
  std::string filename(msg->data, msg->head.size);  // 获取文件名
  if (filename.empty()) return;

  std::string filepath = get_current_directory() + filename;
  std::cout << "[INFO] Client Download file: " << filepath << std::endl;

  // 打开文件获取大小
  inputfile_.open(filepath, std::ios::in | std::ios::binary | std::ios::ate);
  if (!inputfile_.is_open()) {
    std::cout << "[ERROR] Failed to open file for reading: " << filepath
              << std::endl;
    return;
  }
  file_size_ = inputfile_.tellg();
  inputfile_.seekg(0, std::ios::beg);
  std::cout << "[INFO] open file: " << filepath << " size: " << file_size_
            << std::endl;

  // 发送文件名和文件大小
  char buf[1024];
  snprintf(buf, 1024, "%s,%d", filename.c_str(), file_size_);

  // 回复消息 MSG_TYPE_DOWNLOAD_ACCEPT
  Message _msg;
  _msg.head.type = MSG_TYPE_DOWNLOAD_ACCEPT;
  _msg.head.size = strlen(buf);
  _msg.data = buf;
  WriteMessage(&_msg);
}

}  // namespace ZeDisk